﻿IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DequeueEntries]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[DequeueEntries]
GO
CREATE PROCEDURE [dbo].[DequeueEntries]
    @count int,
    @machineName nvarchar(100),
    @processId int,
    @appDomainId int,
    @processorId nvarchar(100),
    @returnCode int output,
    @batchId uniqueidentifier output
AS 
BEGIN
    SET NOCOUNT ON;
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED

    DECLARE @currentTime datetime2
    SET @currentTime = SYSUTCDATETIME()
    SET @batchId = NEWID()
    SET @returnCode = 0
    BEGIN TRY
        BEGIN TRAN T1

        UPDATE TOP(@count) QueueEntry
        -- WITH (ROWLOCK, XLOCK, HOLDLOCK)
        WITH (UPDLOCK, ROWLOCK, READPAST)
        SET
            StateId = 2,
            MachineName = @machineName,
            ProcessId = @processId,
            ProcessorId = @processorId,
            BatchId = @batchId,
            DequeueTime = @currentTime,
            DequeueAttemptCount = DequeueAttemptCount + 1
            WHERE
                StateId = 1 AND
                BatchId IS NULL AND
                DeliveryAttemptCount < MaxDeliveryAttemptCount AND
                (ExpirationTime IS NULL OR
                    ExpirationTime < @currentTime) AND
                ((IsResponse = 0) OR
                    (IsResponse = 1 AND
                    ReceiverMachineName = @machineName AND
                    ReceiverProcessId = @processId AND
                    ReceiverAppDomainId = @appDomainId))

        SELECT
            qe.[Id],
            qe.MessageId,
            qe.RoutingHeader,
            qe.Priority,
            qe.OrderedDelivery,
            qe.ReceiverMachineName,
            qe.ReceiverProcessId,
            qe.ReceiverAppDomainId,
            qe.EnqueueTime,
            qe.ExpirationTime,
            qe.StateId,
            qe.MachineName,
            qe.ProcessId,
            qe.ProcessorId,
            qe.BatchId,
            qe.DequeueTime,
            qe.DequeueAttemptCount,
            qe.DeliveryAttemptCount,
            qe.IsResponse,
            m.PartCount,
            m.Size,
            m.CorrelationId,
            m.MessageVersion,
            m.Action,
            m.ReceiveTime,
            m.ReceiveAddress,
            m.CreateTime
        FROM QueueEntry qe WITH (NOLOCK), Message m WITH (NOLOCK)
        WHERE
            qe.BatchId = @batchId AND
            qe.MessageId = m.Id
        ORDER BY
            [Priority] DESC, [Id] ASC

        COMMIT TRAN T1

    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK TRAN T1

        SET @batchId = NULL
        SET @returnCode = 1

        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;

        SELECT @ErrorMessage = ERROR_MESSAGE(),
                @ErrorSeverity = ERROR_SEVERITY(),
                @ErrorState = ERROR_STATE();

        RAISERROR (@ErrorMessage, -- Message text.
                    @ErrorSeverity, -- Severity.
                    @ErrorState -- State.
                    );
    END CATCH
END
GO

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[CreateMessage]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[CreateMessage]
GO
CREATE PROCEDURE [dbo].[CreateMessage]
    @correlationId nvarchar(100),
    @messageVersion nvarchar(255),
    @action nvarchar(255),
    @receiveTime datetime2,
    @receiveAddress nvarchar(max),
    @returnCode int output,
    @messageId bigint output
AS 
BEGIN
    SET NOCOUNT ON;

    DECLARE @currentTime datetime2(7) = SYSUTCDATETIME()

    SET @returnCode = 0
    BEGIN TRY
        INSERT INTO Message
        (
            CorrelationId,
            MessageVersion,
            Action,
            ReceiveTime,
            ReceiveAddress,
            CreateTime
        )
        VALUES
        (
            @correlationId,
            @messageVersion,
            @action,
            @receiveTime,
            @receiveAddress,
            @currentTime
        )
        SET @messageId = SCOPE_IDENTITY()

    END TRY
    BEGIN CATCH
        SET @returnCode = 1

        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;

        SELECT @ErrorMessage = ERROR_MESSAGE(),
                @ErrorSeverity = ERROR_SEVERITY(),
                @ErrorState = ERROR_STATE();

        RAISERROR (@ErrorMessage, -- Message text.
                    @ErrorSeverity, -- Severity.
                    @ErrorState -- State.
                    );
    END CATCH
END
GO
